package niu.toy.spring.mvc;

import niu.toy.spring.ioc.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;

import java.util.List;

/**
 * 拦截器链:由被拦截方法handler和拦截器组成 ；由HandlerMapping返回
 * @author niu
 */
public class HandlerExecutionChain {
    private static final Logger logger = LoggerFactory.getLogger(HandlerExecutionChain.class);
    private final Object handler;


    @Nullable
    private List<HandlerInterceptor> interceptorList=new ArrayList<>();;

    private int interceptorIndex = -1;

    public HandlerExecutionChain(Object handler) {
        this.handler=handler;
    }

    public Object getHandler() {
        return this.handler;
    }

    public void addInterceptor(HandlerInterceptor interceptor) {
        this.interceptorList.add(interceptor);
    }


    boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HandlerInterceptor[] interceptors =this.interceptorList.toArray(new HandlerInterceptor[0]);;
        if (interceptors.length>0) {
            for (int i = 0; i < interceptors.length; i++) {
                HandlerInterceptor interceptor = interceptors[i];
                if (!interceptor.preHandle(request, response, this.handler)) {
                    triggerAfterCompletion(request, response, null);
                    return false;
                }
                this.interceptorIndex = i;
            }
        }
        return true;
    }
    void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
            throws Exception {
        HandlerInterceptor[] interceptors = this.interceptorList.toArray(new HandlerInterceptor[0]);;
        if (interceptors.length>0) {
            for (int i = interceptors.length - 1; i >= 0; i--) {
                HandlerInterceptor interceptor = interceptors[i];
                interceptor.postHandle(request, response, this.handler, mv);
            }
        }
    }
    void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex)
            throws Exception {
        HandlerInterceptor[] interceptors = this.interceptorList.toArray(new HandlerInterceptor[0]);;
        if (interceptors.length>0) {
            for (int i = this.interceptorIndex; i >= 0; i--) {
                HandlerInterceptor interceptor = interceptors[i];
                try {
                    interceptor.afterCompletion(request, response, this.handler, ex);
                }
                catch (Throwable ex2) {
                    logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
                }
            }
        }
    }

    @Override
    public String toString() {
        Object handler = getHandler();
        StringBuilder sb = new StringBuilder();
        sb.append("HandlerExecutionChain with handler [").append(handler).append("]");
        HandlerInterceptor[] interceptors = this.interceptorList.toArray(new HandlerInterceptor[0]);;
        if (interceptors.length>0) {
            sb.append(" and ").append(interceptors.length).append(" interceptor");
            if (interceptors.length > 1) {
                sb.append("s");
            }
        }
        return sb.toString();
    }
}
